﻿#include "MysqlDao.h"
#include "ConfigMgr.h"

MysqlDao::MysqlDao()
{
	auto & cfg = ConfigMgr::Inst();
	const auto& host = cfg["Mysql"]["Host"];
	const auto& port = cfg["Mysql"]["Port"];
	const auto& pwd = cfg["Mysql"]["Password"];
	const auto& schema = cfg["Mysql"]["Schema"];
	const auto& user = cfg["Mysql"]["User"];
	pool_.reset(new MySqlPool(host+":"+port, user, pwd,schema, 5));
}

MysqlDao::~MysqlDao(){
	pool_->Close();
}

int MysqlDao::RegUserTransaction(const std::string& name, const std::string& email, const std::string& pwd)
{
	// 生成密码哈希future对象为了和sql事务并行执行
	auto hashFuture = _bcryptWorker.generateHashAsync(pwd);

	auto con = pool_->getConnection();
	if (!con) return -1;

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		//开始事务
		con->_con->setAutoCommit(false);

		//执行第一个数据库操作，根据email查找用户是否存在
		// 准备查询语句
		std::unique_ptr<sql::PreparedStatement> pstmt_email(con->_con->prepareStatement("SELECT 1 FROM user WHERE email = ?"));

		// 绑定参数
		pstmt_email->setString(1, email);

		// 执行查询
		std::unique_ptr<sql::ResultSet> res_email(pstmt_email->executeQuery());

		auto email_exist = res_email->next();
		if (email_exist) {
			con->_con->rollback();
			std::cout << "email " << email << " exist" <<std::endl;
			return 0;
		}

		// 确保哈希完成 
		auto hash_pwd = hashFuture.get();
		std::cout<<hash_pwd<<std::endl;

		//  插入用户数据
		std::unique_ptr<sql::PreparedStatement> pstmt_insert(
			con->_con->prepareStatement(
				"INSERT INTO user (email, password_hash, user_name) "
				"VALUES (?, ?, ?)"
			)
		);
		pstmt_insert->setString(1, email);
		pstmt_insert->setString(2, hash_pwd);
		pstmt_insert->setString(3, name);
		pstmt_insert->executeUpdate();

		// ▶ 获取自增UID（通过独立查询）
		std::unique_ptr<sql::Statement> stmt(con->_con->createStatement());
		std::unique_ptr<sql::ResultSet> res(stmt->executeQuery("SELECT LAST_INSERT_ID()"));
		int newId = 0;
		if (res->next()) {
			newId = res->getInt(1);
		}
		else {
			con->_con->rollback();
			return -1;
		}

		con->_con->commit();
		return newId; // 成功返回新UID 
	}
	catch (sql::SQLException& e) {
		std::cerr << "数据库异常: " << e.what()
			<< "\n错误代码: " << e.getErrorCode()
			<< "\nSQL状态: " << e.getSQLState() << std::endl;
		return -1;
	}
}

//需要邮箱存在
int MysqlDao::CheckEmail_reset(const std::string& email)
{
	auto con = pool_->getConnection();
	if (con == nullptr) {
		return false;
	}

	Defer defer([this, &con] {
		pool_->returnConnection(std::move(con));
		});

	try {
		//开始事务
		con->_con->setAutoCommit(false);
		//执行第一个数据库操作，根据email查找用户
		// 准备查询语句

		std::unique_ptr<sql::PreparedStatement> pstmt_email(con->_con->prepareStatement("SELECT 1 FROM user WHERE email = ?"));

		// 绑定参数
		pstmt_email->setString(1, email);

		// 执行查询
		std::unique_ptr<sql::ResultSet> res_email(pstmt_email->executeQuery());

		auto email_exist = res_email->next();
		// 如果查询结果不为空，表示邮箱已存在
		if (email_exist) {
			con->_con->rollback();
			std::cout << "email " << email << " is valid";
			return ErrorCodes::Success;
		}
		return ErrorCodes::EmailNotExist;
	}
	catch (sql::SQLException& e) {
		// 如果发生错误，回滚事务
		if (con) {
			con->_con->rollback();
		}
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return -1;
	}
	return 0;
}

//需要邮箱不存在
int MysqlDao::CheckEmail_reg(const std::string& email)
{
	auto con = pool_->getConnection();
	if (con == nullptr) {
		return false;
	}

	Defer defer([this, &con] {
		pool_->returnConnection(std::move(con));
		});

	try {
		//开始事务
		con->_con->setAutoCommit(false);
		//执行第一个数据库操作，根据email查找用户
		// 准备查询语句

		std::unique_ptr<sql::PreparedStatement> pstmt_email(con->_con->prepareStatement("SELECT 1 FROM user WHERE email = ?"));

		// 绑定参数
		pstmt_email->setString(1, email);

		// 执行查询
		std::unique_ptr<sql::ResultSet> res_email(pstmt_email->executeQuery());

		auto email_exist = res_email->next();
		// 如果查询结果不为空，表示邮箱已存在
		if (email_exist) {
			con->_con->rollback();
			std::cout << "email " << email << " is valid";
			return ErrorCodes::EmailExist;
		}
		return ErrorCodes::Success;
	}
	catch (sql::SQLException& e) {
		// 如果发生错误，回滚事务
		if (con) {
			con->_con->rollback();
		}
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return -1;
	}
	return 0;
}

bool MysqlDao::UpdatePwd(const std::string& email, const std::string& new_pwd) {
	// 生成密码哈希future对象为了和sql事务并行执行
	auto hashFuture = _bcryptWorker.generateHashAsync(new_pwd);

	auto con = pool_->getConnection();

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		if (con == nullptr) {
			return false;
		}

		// 准备查询语句
		std::unique_ptr<sql::PreparedStatement> pstmt(con->_con->prepareStatement("UPDATE user SET password_hash = ? WHERE email = ?"));

		// 哈希结果 
		auto hash_pwd = hashFuture.get();
		// 绑定参数
		pstmt->setString(1, hash_pwd);
		pstmt->setString(2, email);

		// 执行更新
		int updateCount = pstmt->executeUpdate();
		std::cout << "Updated rows: " << updateCount << std::endl;
		return true;
	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return false;
	}
}

//检查邮箱对应的密码是否正确
bool MysqlDao::CheckPwd(const std::string& email, const std::string& pwd, UserInfo& userInfo) {
	auto con = pool_->getConnection();
	if (!con) return false;

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		// STEP 1: 原子化获取用户数据 
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT uid, email, password_hash, user_name FROM user WHERE email = ?"
			)
		);
		pstmt->setString(1, email);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		if (!res->next()) return false; // 用户不存在 

		// STEP 2: 创建版本感知上下文 
		auto ctx = std::make_shared<ValidationContext>();
		const std::string dbHash = res->getString("password_hash");
		ctx->updateHash(dbHash); // 初始化上下文 

		// STEP 3: 异步验证（无并行任务时仍保持异步优势）
		std::future<bool> validFuture = _bcryptWorker.validatePasswordAsync(pwd, ctx);

		// STEP 4: 同步等待（优化点：可设置超时避免死锁）
		if (!validFuture.get())  return false;

		// STEP 5: 填充用户数据 
		userInfo.uid = res->getInt("uid");
		userInfo.name = res->getString("user_name");
		userInfo.email = res->getString("email");
		return true;
	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException: " << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return false;
	}
	catch (...) {
		return false; // BCrypt异常统一处理 
	}
}

int MysqlDao::CheckFileHash(const std::string& file_hash)
{
	auto con = pool_->getConnection();
	if (!con) return -1;

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement("SELECT file_id FROM file_info WHERE file_hash = ? LIMIT 1")
		);
		pstmt->setString(1, file_hash);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		if (res->next()) {
			return res->getInt("file_id");
		}
		return -1; // 哈希不存在
	}
	catch (sql::SQLException& e) {
		std::cerr << "CheckFileHash error: " << e.what() << std::endl;
		return -1;
	}
}

//添加文件事务
int MysqlDao::AddFileTransaction(int user_id,
	const std::string& storage_path,
	const std::string& logical_name,
	const std::string& process_type,
	const std::string& file_hash,
	int belong_id)
{
	auto con = pool_->getConnection();
	if (!con) return -1;

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		con->_con->setAutoCommit(false);

		// 插入新记录
		std::unique_ptr<sql::PreparedStatement> pstmt_insert(
			con->_con->prepareStatement(
				"INSERT INTO file_info "
				"(user_id, storage_path, logical_name, process_type, file_hash, belong_server_id) "
				"VALUES (?, ?, ?, ?, ?, ?)"
			)
		);
		pstmt_insert->setInt(1, user_id);
		pstmt_insert->setString(2, storage_path);
		pstmt_insert->setString(3, logical_name);
		pstmt_insert->setString(4, process_type);
		pstmt_insert->setString(5, file_hash);
		pstmt_insert->setInt(6, belong_id);
		pstmt_insert->executeUpdate();

		// 获取新file_id
		std::unique_ptr<sql::Statement> stmt(con->_con->createStatement());
		std::unique_ptr<sql::ResultSet> res_id(stmt->executeQuery("SELECT LAST_INSERT_ID()"));
		int new_file_id = -1;
		if (res_id->next()) {
			new_file_id = res_id->getInt(1);
		}

		con->_con->commit();
		return new_file_id;
	}
	catch (sql::SQLException& e) {
		std::cerr << "AddFile error: " << e.what() << std::endl;
		if (con) con->_con->rollback();
		return -1;
	}
}

//获取文件路径
std::string MysqlDao::GetFilePath(const std::string& file_hash)
{
	auto con = pool_->getConnection();
	if (!con) return "";

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT storage_path FROM file_info "
				"WHERE file_hash = ? LIMIT 1"
			)
		);
		pstmt->setString(1, file_hash);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		if (res->next()) {
			return res->getString("storage_path");
		}
		return ""; // 未找到记录

	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException in GetFilePath: " << e.what()
			<< "\nError code: " << e.getErrorCode()
			<< "\nSQLState: " << e.getSQLState() << std::endl;
		return "";
	}
}

std::string MysqlDao::GetFilePath(int file_id)
{
	auto con = pool_->getConnection();
	if (!con) return "";

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT storage_path FROM file_info "
				"WHERE file_id = ? LIMIT 1"
			)
		);
		pstmt->setInt(1, file_id);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		if (res->next()) {
			return res->getString("storage_path");
		}
		return ""; // 未找到记录

	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException in GetFilePath: " << e.what()
			<< "\nError code: " << e.getErrorCode()
			<< "\nSQLState: " << e.getSQLState() << std::endl;
		return "";
	}
}

std::string MysqlDao::GetLogicalName(int file_id)
{
	auto con = pool_->getConnection();
	if (!con) return "";

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT logical_name FROM file_info "
				"WHERE file_id = ? LIMIT 1"
			)
		);
		pstmt->setInt(1, file_id);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		if (res->next()) {
			return res->getString("logical_name");
		}
		return ""; // 未找到记录

	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException in GetFilePath: " << e.what()
			<< "\nError code: " << e.getErrorCode()
			<< "\nSQLState: " << e.getSQLState() << std::endl;
		return "";
	}
}

//获取该用户所有的文件元数据
Json::Value MysqlDao::GetFilesByUser(int user_id)
{
	Json::Value result;
	result["error"] = "success";

	auto con = pool_->getConnection();
	if (!con) {
		result["error"] = "Database connection failed";
		return result;
	}

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT file_id, storage_path, upload_time, "
				"logical_name, process_type, file_hash "
				"FROM file_info WHERE user_id = ? "
				"ORDER BY upload_time DESC"
			)
		);
		pstmt->setInt(1, user_id);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		Json::Value files(Json::arrayValue);
		while (res->next()) {
			Json::Value file;
			file["file_id"] = res->getInt("file_id");
			file["storage_path"] = res->getString("storage_path").c_str();
			file["upload_time"] = res->getString("upload_time").c_str();
			file["logical_name"] = res->getString("logical_name").c_str();
			file["process_type"] = res->getString("process_type").c_str();
			file["file_hash"] = res->getString("file_hash").c_str();
			files.append(file);
		}
		result["files"] = files;

	}
	catch (sql::SQLException& e) {
		result["code"] = -2;
		result["msg"] = "Database error: " + std::string(e.what());
		std::cerr << "SQLException in GetFilesByUser: " << e.what()
			<< "\nError code: " << e.getErrorCode()
			<< "\nSQLState: " << e.getSQLState() << std::endl;
	}
	return result;
}

std::shared_ptr<UserInfo> MysqlDao::GetUser(int uid)
{
	auto con = pool_->getConnection();
	if (!con) {
		return nullptr;
	}
	std::shared_ptr<UserInfo> user_ptr = nullptr;
	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT uid, email, password_hash, user_name FROM user WHERE uid = ?"
			)
		);
		pstmt->setInt(1, uid);

		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		// 遍历结果集
		while (res->next()) {
			user_ptr.reset(new UserInfo);
			user_ptr->uid = res->getInt("uid");
			user_ptr->email = res->getString("email");
			user_ptr->pwd = res->getString("password_hash");
			user_ptr->name = res->getString("user_name");
			break;
		}
		return user_ptr;
	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException in GetUser" << e.what();
		std::cerr << " (MySQL error code: " << e.getErrorCode();
		std::cerr << ", SQLState: " << e.getSQLState() << " )" << std::endl;
		return nullptr;
	}
}

int MysqlDao::findFileBelong(int file_id)
{
	auto con = pool_->getConnection();
	if (!con) return -1;

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT belong_server_id FROM file_info "
				"WHERE file_id = ? LIMIT 1"
			)
		);
		pstmt->setInt(1, file_id);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		if (res->next()) {
			return res->getInt("belong_server_id");//返回找到的文件所属服务器
		}
		return -1; // 未找到记录
	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException in GetFilePath: " << e.what()
			<< "\nError code: " << e.getErrorCode()
			<< "\nSQLState: " << e.getSQLState() << std::endl;
		return -1;
	}
}

std::string MysqlDao::GetFileHash(int file_id)
{
	auto con = pool_->getConnection();
	if (!con) return "";

	Defer defer([this, &con] { pool_->returnConnection(std::move(con)); });

	try {
		std::unique_ptr<sql::PreparedStatement> pstmt(
			con->_con->prepareStatement(
				"SELECT file_hash FROM file_info "
				"WHERE file_id = ? LIMIT 1"
			)
		);
		pstmt->setInt(1, file_id);
		std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

		if (res->next()) {
			return res->getString("file_hash");
		}
		return ""; // 未找到记录

	}
	catch (sql::SQLException& e) {
		std::cerr << "SQLException in GetFileHash: " << e.what()
			<< "\nError code: " << e.getErrorCode()
			<< "\nSQLState: " << e.getSQLState() << std::endl;
		return "";
	}
}
